#include "zrpc/http/http_server.h"

#include "zrpc/base/buffer.h"
#include "zrpc/net/socket.h"
#include "zrpc/base/logger.h"
namespace zrpc {
HttpServer::HttpServer(const std::string &ip, uint16_t port)
    : server_(&loop_, ip, port, nullptr) {
  server_.SetConnectionCallback(
      std::bind(&HttpServer::OnConnection, this, std::placeholders::_1));
  server_.SetMessageCallback(std::bind(&HttpServer::OnMessage, this,
                                       std::placeholders::_1,
                                       std::placeholders::_2));
}

void HttpServer::SetMessageCallback(HttpCallBack callback) {
  http_callback_ = callback;
}

HttpServer::~HttpServer() {}

void HttpServer::HttpClientTimerCallback(const std::thread::id &threadId) {
  auto it = connection_buckets_.find(threadId);
  assert(it != connection_buckets_.end());
  if (it->second.size() >= kIdleSecond) {
    it->second.pop_front();
  }
  it->second.push_back(Bucket());
  DumpBuckets();
}

void HttpServer::Run() { loop_.Run(); }

void HttpServer::Start() {
  server_.Start();

  auto pools = server_.GetThreadPool()->GetAllLoops();

  for (int i = 0; i < pools.size(); i++) {
    WeakConnectionList buckets;
    buckets.resize(kIdleSecond);
    connection_buckets_[pools[i]->GetThreadId()] = buckets;
    pools[i]->RunAfter(kTimer, true,
                       std::bind(&HttpServer::HttpClientTimerCallback, this,
                                 pools[i]->GetThreadId()));
  }
}

void HttpServer::OnConnection(const std::shared_ptr<TcpConnection> &conn) {
  if (conn->Connected()) {

    std::shared_ptr<HttpContext> c(new HttpContext());
     conn->SetContext(c);
  } else {

  }
}

void HttpServer::DumpBuckets() {
  return;
  auto it = connection_buckets_.find(std::this_thread::get_id());
  assert(it != connection_buckets_.end());

  int idx = 0;
  for (auto bucketI = it->second.begin(); bucketI != it->second.end();
       ++bucketI, ++idx) {
    const Bucket &bucket = *bucketI;
    printf("[%d] len = %zd : ", idx, bucket.size());
    for (auto it = bucket.begin(); it != bucket.end(); ++it) {
      bool connectionDead = (*it)->weak_conn_.expired();
      printf("%p(%lld)%s, ", (*it).get(), it->use_count(),
             connectionDead ? " DEAD" : "");
    }
    puts("");
  }
}

void HttpServer::OnMessage(const std::shared_ptr<TcpConnection> &conn,
                           Buffer *buffer) {
  std::shared_ptr<HttpContext> context =
      std::any_cast<std::shared_ptr<HttpContext>>(conn->GetContext());
  if (!context->ParseRequest(buffer)) {
    conn->Send("HTTP/1.1 400 Bad Request\r\n\r\n");
    conn->Shutdown();
    return;
  }

  if (context->GotAll()) {
		context->GetRequest().SetBody(buffer->Peek(),
                                     buffer->Peek() + buffer->ReadableBytes());
    

    if (http_callback_) {
      HttpResponse response;
      http_callback_(conn, context->GetRequest(), &response);
      Buffer buf;
      response.AppendToBuffer(&buf);
      conn->Send(&buf);
      conn->Shutdown();
    }
    context->Reset();
  }
}
}  // namespace zrpc
